package com.umsoft.smart.framework.helper;

import com.umsoft.smart.framework.annotation.Aspect;
import com.umsoft.smart.framework.proxy.AspectProxy;
import com.umsoft.smart.framework.proxy.Proxy;
import com.umsoft.smart.framework.proxy.ProxyManager;
import com.umsoft.smart.framework.proxy.TransactionProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.util.*;


/**
 * 方法拦截类助手
 */
public final class AopHelper {
    private static final Logger LOGGER = LoggerFactory.getLogger(AopHelper.class);



    static {
        Map<Class<?>,Set<Class<?>>> proxyMap = createProxyMap();
        Map<Class<?>,List<Proxy>> targetMap = createTargetMap(proxyMap);
        targetMap.forEach((k,v)->{
            Object proxy = ProxyManager.createProxy(k,v);
            BeanHelper.setBean(k,proxy);
        });

    }


    /**
     * 创建包含 Aspect 注解的所有类
     * @param aspect
     * @return
     */
    private static Set<Class<?>> createTargetClassSet(Aspect aspect){
        Set<Class<?>> targetClassSet = new HashSet<>();
        Class<? extends Annotation> annotation = aspect.value();
        if(annotation != null && !annotation.equals(Aspect.class)){
            targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation));
        }
        return targetClassSet;
    }

    private static void addAspectProxy(Map<Class<?>,Set<Class<?>>> proxyMap){
        Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
        proxyClassSet.stream().forEach(data->{
            if(data.isAnnotationPresent(Aspect.class)){
                Aspect aspect = data.getAnnotation(Aspect.class);
                Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
                proxyMap.put(data,targetClassSet);
            }
        });
    }

    /**
     * 获取代理类和目标类集合间的关系
     * @return
     */
    private static Map<Class<?>,Set<Class<?>>> createProxyMap(){
        Map<Class<?>,Set<Class<?>>> proxyMap = new HashMap<>();
        addAspectProxy(proxyMap);
        addTransactionProxy(proxyMap);
        return proxyMap;
    }

    private static void addTransactionProxy(Map<Class<?>,Set<Class<?>>> proxyMap) {
        Set<Class<?>> serviceClassSet = ClassHelper.getServiceClassSet();
        proxyMap.put(TransactionProxy.class,serviceClassSet);
    }

    /**
     * 获取目标类与代理对象列表之间的映射关系
     * @param proxyMap
     * @return
     */
    private static Map<Class<?>,List<Proxy>> createTargetMap(Map<Class<?>,Set<Class<?>>> proxyMap){
        Map<Class<?>,List<Proxy>> targetMap = new HashMap<>();
        proxyMap.forEach((k,v)->{
            v.stream().forEach(data->{
                try {
                    Proxy proxy = (Proxy) k.newInstance();
                    if(targetMap.containsKey(k)){
                        targetMap.get(k).add(proxy);
                    }else {
                        List<Proxy> proxyList = new ArrayList<>();
                        proxyList.add(proxy);
                        targetMap.put(k,proxyList);
                    }
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            });
        });
        return targetMap;
    }

}
